package com.zynn.service.module.es.service;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.google.common.collect.Lists;
import com.zynn.common.core.utils.SequenceUtil;
import com.zynn.service.module.es.bo.DegOneFrientWithWeight;
import com.zynn.service.module.es.constant.ConstantUtil;
import com.zynn.service.module.es.dao.ProductBaseUserCacheMapper;
import com.zynn.service.module.es.entity.ProductBaseUserCache;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author 刘猛
 * @description 初始化每个用户的一度好友
 * @create 2018-10-09 13:26
 **/
@Slf4j
@Service
public class InitProductUserFriendsService {

    @Autowired
    private RestHighLevelClient client;

    @Autowired
    private ProductBaseUserCacheMapper productBaseUserCacheMapper;

    private static final int CALC_TYPE_01 = 1;
    private static final int CALC_TYPE_02 = 2;
    private static final int CALC_TYPE_03 = 3;
    private static final int CALC_TYPE_04 = 4;
    private static final int CALC_TYPE_05 = 5;
    private static final int CALC_TYPE_06 = 6;
    private static final int CALC_TYPE_07 = 7;
    private static final int CALC_TYPE_08 = 8;
    private static final int CALC_TYPE_09 = 9;
    private static final int CALC_TYPE_10 = 10;
    private static final int CALC_TYPE_11 = 11;
    private static final int CALC_TYPE_12 = 12;
    private static final int CALC_TYPE_13 = 13;
    private static final int CALC_TYPE_14 = 14;

    /**
     * 计算一个用户的好友(产品版推荐)
     * @param userId
     */
    public void initPorductUserFriendsWithWeight(Long userId) {
        List<DegOneFrientWithWeight> recommendListDegAll = this.queryUserRecommendWithWeightDegAll(userId);
        if(!CollectionUtils.isEmpty(recommendListDegAll)){
            List<String> productFriendWithWeight = recommendListDegAll.stream().map((e) -> e.getWeight() +"|"+ e.getUserId()).collect(Collectors.toList());
            this.syncProductDegOneFriends(userId,null,productFriendWithWeight);
        }
    }


    /**
     * 将推荐好友信息同步到es
     * @param userId
     * @param userIdList
     * @param friendWithWeight
     */
    private void syncProductDegOneFriends(Long userId, List<Long> userIdList, List<String> friendWithWeight) {
        if(RecommandUtil.existsIndex(userId,client)){
            this.updateProductIndex(userId,friendWithWeight);
        }else{
            this.createProductIndex(userId,userIdList,friendWithWeight);
        }
    }

    /**
     * 产品版推荐索引（更新）
     * @param userId
     * @param userIdList
     * @param friendWithWeight
     */
    private void updateProductIndex(Long userId,List<String> friendWithWeight){
        Map<String, Object> jsonMap = new HashMap<>(20);
        jsonMap.put("product_deg_one_friend", friendWithWeight);

        //Map会自动转换为JSON格式的文档源
        UpdateRequest indexRequest = new UpdateRequest("user_friend_index", "_doc", userId.toString())
                .doc(jsonMap);
        UpdateResponse indexResponse = null;
        try {
            indexResponse = client.update(indexRequest);
            log.info(indexResponse.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 产品版推荐索引（创建）
     * @param userId
     * @param userIdList
     * @param friendWithWeight
     */
    private void createProductIndex(Long userId, List<Long> userIdList, List<String> friendWithWeight){
        Map<String, Object> jsonMap = new HashMap<>(20);
        jsonMap.put("user_id", userId);
        jsonMap.put("deg_one_frient", userIdList);
        jsonMap.put("product_deg_one_friend", friendWithWeight);

        //Map会自动转换为JSON格式的文档源
        IndexRequest indexRequest = new IndexRequest("user_friend_index", "_doc", userId.toString())
                .source(jsonMap);
        IndexResponse indexResponse = null;
        try {
            indexResponse = client.index(indexRequest);
            log.info(indexResponse.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 产品版用户推荐（核心方法）
     * @param userId
     * @return
     */
    public List<DegOneFrientWithWeight> queryUserRecommendWithWeightDegAll(Long userId) {
        List<DegOneFrientWithWeight> recommendFriendsAll = Lists.newLinkedList();
        Map<String,Object> params = new HashMap<>(8);

        /**
         * 1、一度用户为同在一个相册（相册人数少于200）的用户（不含活动相册，市场相关相册）
         */
        Long sequenceId = SequenceUtil.getId();
        try {
            /**
             * 缓存推荐用户基数
             */
            productBaseUserCacheMapper.insertProductBaseRecommendUsers2CacheTable(sequenceId,userId,ConstantUtil.MAX_GROUP_MEMBERS);

            /**
             * 一度推荐用户
             */
            this.mergeRecommendUsers(userId,sequenceId,ConstantUtil.CALC_TYPE_01,params,recommendFriendsAll);
            this.mergeRecommendUsers(userId,sequenceId,ConstantUtil.CALC_TYPE_02,params,recommendFriendsAll);
            this.mergeRecommendUsers(userId,sequenceId,ConstantUtil.CALC_TYPE_03,params,recommendFriendsAll);
            this.mergeRecommendUsers(userId,sequenceId,ConstantUtil.CALC_TYPE_04,params,recommendFriendsAll);
            this.mergeRecommendUsers(userId,sequenceId,ConstantUtil.CALC_TYPE_05,params,recommendFriendsAll);
            this.mergeRecommendUsers(userId,sequenceId,ConstantUtil.CALC_TYPE_06,params,recommendFriendsAll);
            this.mergeRecommendUsers(userId,sequenceId,ConstantUtil.CALC_TYPE_07,params,recommendFriendsAll);
            this.mergeRecommendUsers(userId,sequenceId,ConstantUtil.CALC_TYPE_08,params,recommendFriendsAll);
            this.mergeRecommendUsers(userId,sequenceId,ConstantUtil.CALC_TYPE_09,params,recommendFriendsAll);
            this.mergeRecommendUsers(userId,sequenceId,ConstantUtil.CALC_TYPE_10,params,recommendFriendsAll);
            this.mergeRecommendUsers(userId,sequenceId,ConstantUtil.CALC_TYPE_11,params,recommendFriendsAll);
            this.mergeRecommendUsers(userId,sequenceId,ConstantUtil.CALC_TYPE_12,params,recommendFriendsAll);
            this.mergeRecommendUsers(userId,sequenceId,ConstantUtil.CALC_TYPE_13,params,recommendFriendsAll);
            this.mergeRecommendUsers(userId,sequenceId,ConstantUtil.CALC_TYPE_14,params,recommendFriendsAll);


            if(!CollectionUtils.isEmpty(recommendFriendsAll)){
                /**
                 * 排除自己
                 */
                RecommandUtil.removeMyself(recommendFriendsAll,userId);
                /**
                 * 推荐用户重复时，选择分数高者
                 */
                RecommandUtil.getHightestScoreRecommendUser(recommendFriendsAll);
            }
        }catch(Exception e){
            log.error("产品推荐计算错误！",e);
        }finally {
            // 最后删除掉中间临时数据
            productBaseUserCacheMapper.delete(new EntityWrapper<ProductBaseUserCache>().eq("sequence_id",sequenceId));
        }
        return recommendFriendsAll;
    }


    /**
     * 查询不同条件的推荐用户
     * @param userId
     * @param sequenceId
     * @param calcType
     * @param params
     * @param allRecommendList
     */
    public void mergeRecommendUsers(Long userId,Long sequenceId,int[] calcType,Map<String,Object> params,List<DegOneFrientWithWeight> allRecommendList){
        params.clear();
        params.put("userId",userId);
        params.put("sequenceId",sequenceId);
        params.put("score",calcType[1]);
        List<DegOneFrientWithWeight> reommendList = null;
        switch (calcType[0]){
            case CALC_TYPE_01: reommendList = productBaseUserCacheMapper.queryUserRecommendCondOne(params);break;
            case CALC_TYPE_02: reommendList = productBaseUserCacheMapper.queryUserRecommendCondTwo(params);break;
            case CALC_TYPE_03: reommendList = productBaseUserCacheMapper.queryUserRecommendCondThree(params);break;
            case CALC_TYPE_04: reommendList = productBaseUserCacheMapper.queryUserRecommendCondFour(params);break;
            case CALC_TYPE_05: reommendList = productBaseUserCacheMapper.queryUserRecommendCondFive(params);break;
            case CALC_TYPE_06: reommendList = productBaseUserCacheMapper.queryUserRecommendCondSix(params);break;
            case CALC_TYPE_07: reommendList = productBaseUserCacheMapper.queryUserRecommendCondSeven(params);break;
            case CALC_TYPE_08: reommendList = productBaseUserCacheMapper.queryUserRecommendCondEight(params);break;
            case CALC_TYPE_09: reommendList = productBaseUserCacheMapper.queryUserRecommendCondNine(params);break;
            case CALC_TYPE_10: reommendList = productBaseUserCacheMapper.queryUserRecommendCondTen(params);break;
            case CALC_TYPE_11: reommendList = productBaseUserCacheMapper.queryUserRecommendCondEleven(params);break;
            case CALC_TYPE_12: reommendList = productBaseUserCacheMapper.queryUserRecommendCondTwelve(params);break;
            case CALC_TYPE_13: reommendList = productBaseUserCacheMapper.queryUserRecommendCondThirteen(params);break;
            case CALC_TYPE_14: reommendList = productBaseUserCacheMapper.queryUserRecommendCondFourteen(params);break;
            default: break;
        }
        if(!CollectionUtils.isEmpty(reommendList)){
            allRecommendList.addAll(reommendList);
        }
    }
}
